#define _GNU_SOURCE
#include "app_serial.h"
#include "log/log.h"

int app_serial_setBaudRate(Device_t *device, BaudRate rate)
{
    // 获取串口当前配置属性
    struct termios attr;
    tcgetattr(device->fd, &attr);

    // 修改属性(波特率)
    cfsetspeed(&attr, rate);

    // 设置串口属性 
    int result = tcsetattr(device->fd, TCSAFLUSH, &attr);
    if (result != 0) {
        log_error("设置串口波特率失败");
        return -1;
    }
    log_debug("设置串口波特率成功");
    return 0;
}

int app_serial_setParity(Device_t *device, Parity parity)
{
    // 获取串口当前配置属性
    struct termios attr;
    tcgetattr(device->fd, &attr);

    // 修改属性(验证位)
    attr.c_cflag &= ~(PARENB | PARODD); // 清除验证位
    attr.c_cflag |= parity; // 设置验证位
    

    // 设置串口属性 (当前不生效， 调用flush后才生效)
    int result = tcsetattr(device->fd, TCSAFLUSH, &attr);
    if (result != 0) {
        log_error("设置串口校验位失败");
        return -1;
    }
    log_debug("设置串口校验位成功");
    return 0;
}

int app_serial_setStopBits(Device_t *device, StopBits stopBits)
{
    // 获取串口当前配置属性
    struct termios attr;
    tcgetattr(device->fd, &attr);

    // 修改属性(停止位)
    attr.c_cflag &= ~CSTOPB; // 清除停止位
    attr.c_cflag |= stopBits; // 设置停止位

    // 设置串口属性 (当前不生效， 调用flush后才生效)
    int result = tcsetattr(device->fd, TCSAFLUSH, &attr);
    if (result != 0) {
        log_error("设置串口停止位失败");
        return -1;
    }
    log_debug("设置串口停止位成功");
    return 0;
}

int app_serial_setBlock(Device_t *device, int is_block)
{
    // 获取串口当前配置属性
    struct termios attr;
    tcgetattr(device->fd, &attr);

    // 修改属性(阻塞/非阻塞)
    if (is_block) { // 阻塞
        attr.c_cc[VMIN] = 1; // 至少要读取到一个字节才返回
        attr.c_cc[VTIME] = 0; // 如果没有数据，等待多长时间可以返回， 0：一直等
    } else { // 非阻塞
        attr.c_cc[VMIN] = 0; // 没有读到数据也可以返回
        attr.c_cc[VTIME] = 2; // 单位是100ms, 表示等待200ms / 0.2s 才返回
    }
    

    // 设置串口属性 (当前不生效， 调用flush后才生效)
    int result = tcsetattr(device->fd, TCSAFLUSH, &attr);
    if (result != 0) {
        log_error("设置串口阻塞模式失败");
        return -1;
    }
    log_debug("设置串口阻塞模式成功");
    return 0;
}

int app_serial_setRaw(Device_t *device)
{
    // 获取串口当前配置属性
    struct termios attr;
    tcgetattr(device->fd, &attr);

    // 修改属性(原始模式： 不解析特殊字符)
    cfmakeraw(&attr);

    // 设置串口属性 (当前不生效， 调用flush后才生效)
    int result = tcsetattr(device->fd, TCSAFLUSH, &attr);
    if (result != 0) {
        log_error("设置串口原始模式失败");
        return -1;
    }
    log_debug("设置串口原始模式成功");
    return 0;
}

int app_serial_init(Device_t *device)
{
    // 进行初始化的属性设置
    app_serial_setBaudRate(device, BR_9600); 
    app_serial_setParity(device, Parity_NONE); // 不做校验
    app_serial_setStopBits(device, SB_1); // 1个停止位
    app_serial_setBlock(device, 0); // 非阻塞模式
    app_serial_setRaw(device); // 原始模式

    // 让配置生效
    int result = tcflush(device->fd, TCIOFLUSH);
    if (result != 0) {
        log_error("串口初始化失败");
        return -1;
    }
    log_debug("串口初始化成功");
    return 0;
}

int app_serial_flush(Device_t *device)
{
    int result = tcflush(device->fd, TCIOFLUSH);
    return result;
}